//
//  FreeListAllocator.cpp
//  MemoryManager
//
//  Created by Bram Buurlage on 7/2/12.
//  Copyright (c) 2012 Bram Buurlage. All rights reserved.
//

#include <iostream>
#include <cmath>
#include <cassert>

#include "FreeListAllocator.h"
#include "BuddyAllocator.h"

FreeListAllocator::FreeListAllocator(): Allocator("Power of 2 Free-list")
{
    baselog = std::log(2.0);
    headers = 0x0;
    
    nextbase = 0;
}

FreeListAllocator::~FreeListAllocator()
{
}

void FreeListAllocator::printFragmentation()
{
    int i=0;
    for (int x=minpower; x<=maxpower; ++x)
    {
        headers[i++]->printFragmentation();
    }
}

const Area* FreeListAllocator::alloc(int wanted)
{
    wanted += sizeof(void*);
    if (wanted > 1024) return 0x0;
    
    assert(wanted <= (1 << maxpower));
    int bufsize = (1 << minpower);
    
    int index = 0;
    while (bufsize < wanted) 
    {
        index++;
        bufsize <<= 1;
    }
    
    int cbase = nextbase;
    return headers[index]->alloc(nextbase, size - cbase);
}

void FreeListAllocator::free(const Area* area)
{
    PowerOfTwoArea* a = (PowerOfTwoArea*)area;
    ((ListHeader*)a->header)->free(a);
}

void FreeListAllocator::setSize(int size)
{
    Allocator::setSize(size);
    
    maxpower = (int)(std::log((double)size) / baselog);
    minpower = 4;
    
    std::cout << minpower << "," << maxpower << std::endl;
    
    delete[] headers;
    
    int nheaders = maxpower - minpower;
    headers = new ListHeader*[nheaders];
    
    int i=0;
    for (int p=minpower; p<=maxpower; ++p)
    {
        headers[i] = new ListHeader(1 << p);
        i += 1;
    }
}

ListHeader::ListHeader(int size)
{
    this->size = size;
    this->firstFreeArea = 0x0;
}

ListHeader::~ListHeader()
{
}

void ListHeader::printFragmentation()
{
}

Area* ListHeader::alloc(int& nextbase, int maxsize)
{
    if (firstFreeArea)
    {
        PowerOfTwoArea* area = firstFreeArea;
        firstFreeArea = (PowerOfTwoArea*)firstFreeArea->header;
        
        area->header = (void*)this;
        return area;
    }
    else if (size <= maxsize)
    {
        PowerOfTwoArea* area = new PowerOfTwoArea(nextbase, size);
        nextbase += size;
        
        area->header = (void*)this;
        return area;
    }
    
    return 0x0;
}

void ListHeader::free(PowerOfTwoArea* a)
{
    if (a->header == this)
    {
        a->header = firstFreeArea;
        firstFreeArea = a;
    }
}